#pragma once
#include <unordered_map>
#include <memory>
#include <functional>
#include "Socket.hpp"
#include "Epoller.hpp"
#include "Comm.hpp"
#include "log.hpp"
#include "nocpoy.hpp"

Log lg;

static const uint16_t defaultport = 8080;
static const int num = 128;

class Connection;
class TcpServer;

using func_t = std::function<void(std::weak_ptr<Connection>)>;
using except_t = std::function<void(std::weak_ptr<Connection>)>;

uint32_t EVENT_IN = (EPOLLIN | EPOLLET);
uint32_t EVENT_OUT = (EPOLLOUT | EPOLLET);

class Connection
{
public:
    Connection(int sock)
        : sock_(sock)
    {
    }

    void SetHandler(func_t recv_cb, func_t send_cb, except_t except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }
    int Sockfd()
    {
        return sock_;
    }
    void SetWeak_ptr(std::weak_ptr<TcpServer> tcpserver_ptr)
    {
        _tcpserver_ptr = tcpserver_ptr;
    }
    ~Connection()
    {
    }

    void AppendInfo(const std::string &info)
    {
        _outbuffer += info;
        std::cout << "message: " << _outbuffer << std::endl;
    }

    std::string &Inbuffer() // for debug
    {
        return _inbuffer;
    }
    std::string &Outbuff()
    {
        return _outbuffer;
    }

private:
    int sock_;
    std::string _inbuffer;
    std::string _outbuffer;

public:
    func_t _recv_cb;
    func_t _send_cb;
    except_t _except_cb;

    std::weak_ptr<TcpServer> _tcpserver_ptr;

    std::string _ip;
    uint16_t _port;
};

// *****防止double free，
// 安全返回当前对象的shared_ptr
class TcpServer : public std::enable_shared_from_this<TcpServer>, public nocpoy
{
public:
    TcpServer(uint16_t port = defaultport, func_t OnMessage=nullptr)
        : port_(port),
          OnMessage_(OnMessage),
          listensock_ptr(new Sock()),
          Epoller_ptr(new Epoller())
    {
    }

    void Init()
    {
        listensock_ptr->Socket();
        SetNoBlock(listensock_ptr->Fd());
        listensock_ptr->Bind(port_);
        listensock_ptr->Listen();
        lg(Info, "Init had done,fd:%d", listensock_ptr->Fd());
        AddConnectiom(listensock_ptr->Fd(), EVENT_IN, std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);
    }

    void AddConnectiom(int sock, uint32_t event, func_t recv_cb, func_t send_cb, except_t except_cb,
                       std::string ip = "0.0.0.0", uint16_t port = 0)
    {
        // 给sock建立一个connection对象，将listensock套接字也添加到Connection中，然后将listensock和Connection放到connections
        std::shared_ptr<Connection> new_connection(new Connection(sock));
        new_connection->SetWeak_ptr(shared_from_this()); // 返回当前对象的shared_ptr
        new_connection->SetHandler(recv_cb, send_cb, except_cb);
        new_connection->_ip = ip;
        new_connection->_port = port;
        // 2.添加到unordered_map
        _connections.insert(std::make_pair(sock, new_connection));
        // 3.添加的事件，还要添加到内核中fd,event
        Epoller_ptr->EpollerUpdata(EPOLL_CTL_ADD, sock, event);

        lg(Info, "Add a connection success,sockfd:%d", sock);
    }
    // 连接管理器
    void Accepter(std::weak_ptr<Connection> conn)
    {
        // 加锁,?
        auto connection = conn.lock();
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sock = ::accept(connection->Sockfd(), (struct sockaddr *)&peer, &len);
            if (sock > 0)
            {
                uint16_t peerport = ntohs(peer.sin_port);
                char buffer[128];
                inet_ntop(AF_INET, &peer.sin_addr.s_addr, buffer, sizeof(buffer));
                lg(Info, "get a new client,clientip:%s clientport:%d,sockfd:%d", buffer, peerport, sock);
                AddConnectiom(sock, EVENT_IN, std::bind(&TcpServer::Recver, this, std::placeholders::_1),
                              std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                              std::bind(&TcpServer::Except, this, std::placeholders::_1), buffer, peerport);
                // std::cout << "3333333333" << std::endl;
            }
            else
            {
                std::cout << "failed to accept" << std::endl;
                if (errno == EWOULDBLOCK)
                    break;
                // Interrupted System Call --Error NUM
                if (errno == EINTR)
                    continue;
                else
                    break;
            }
        }
    }

    // 事件管理器
    void Recver(std::weak_ptr<Connection> conn1)
    {
        // std::cout<<"1111111"<<std::endl;
        auto connection = conn1.lock();
        // std::cout << "11111111111 sockfd: " << connection->Sockfd() << std::endl;
        int fd = connection->Sockfd();
        while (true)
        {
            char buffer[128];
            memset(buffer, 0, 128);
            int n = recv(fd, buffer, sizeof(buffer) - 1, 0);
            if (n > 0)
            {
                connection->AppendInfo(buffer);
            }
            else if (n == 0)
            {
                lg(Info, "sockfd: %d, client info %s:%d quit...", fd, connection->_ip.c_str(), connection->_port);
            }
        }
        OnMessage_(connection);
    }
    void Sender(std::weak_ptr<Connection> conn1)
    {
        auto connection = conn1.lock();
        std::string outbuff = connection->Outbuff();
        while (true)
        {
            ssize_t n = send(connection->Sockfd(), outbuff.c_str(), outbuff.size(), 0);
            if (n > 0)
            {
                // 删除已经发过去的数据
                outbuff.erase(0, n);
                if (outbuff.empty())
                    break;
            }
            else if (n == 0)
            {
                return;
            }
            else
            {
                if (errno == EWOULDBLOCK)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    lg(Warning, "client send info error,sockfd:%d,ip:%s,port:%d",
                       connection->Sockfd(), connection->_ip.c_str(), connection->_port);
                    // 回调异常函数
                    connection->_except_cb(connection);
                    break;
                }
            }
        }
        // 是否开启/关闭对事件的关心？
        if (!outbuff.empty())
        {
            // 开启写事件
            EnableEvent(connection->Sockfd(), true, true);
        }
        else
        {
            // 关闭写事件
            EnableEvent(connection->Sockfd(), true, false);
        }
    }
    void Except(std::weak_ptr<Connection> conn1)
    {
        if (conn1.expired())
            return;
        auto connection = conn1.lock();
        int fd = connection->Sockfd();
        lg(Warning, "Excepter hander sock:%d,client info:%s: %d", fd, connection->_ip.c_str(), connection->_port);
        // 1.移除对特定fd的关心
        Epoller_ptr->EpollerUpdata(EPOLL_CTL_DEL, connection->Sockfd(), 0);
        lg(Debug, "close fd:%d done", fd);
        // 2.关闭异常的文件描述符
        close(fd);
        // 3.从unordered_map中移除
        _connections.erase(fd);
    }

    void EnableEvent(int sock, bool readable, bool writeable)
    {
        uint32_t event;
        event = ((readable ? EPOLLIN : 0) | EPOLLET) | ((writeable ? EPOLLOUT : 0) | EPOLLET);
        Epoller_ptr->EpollerUpdata(EPOLL_CTL_MOD, sock, event);
    }
    bool IsEpollSafe(int fd)
    {
        auto iter = _connections.find(fd);
        if (iter == _connections.end())
            return false;
        else
            return true;
    }

    void Dispatcher(int timeout)
    {
        int n = Epoller_ptr->Epoller_wait(revs, num, timeout);
        for (int i = 0; i < n; i++)
        {
            uint32_t event = revs[i].events;
            int sock = revs[i].data.fd;
            std::cout << "事件就绪: sockfd : " << sock << std::endl;
            // 处理EPOLLIN,EPOLLOUT
            if ((event & EPOLLIN) && IsEpollSafe(sock))
            {
                // if(_connections[sock].lock(recv_cb))
                if (_connections[sock]->_recv_cb)
                {
                    _connections[sock]->_recv_cb(_connections[sock]);
                }
            }
            if ((event & EPOLLOUT) && IsEpollSafe(sock))
            {
                if (_connections[sock]->_send_cb)
                {
                    _connections[sock]->_send_cb(_connections[sock]);
                }
            }
        }
    }

    void Loop()
    {
        quit = false;
        while (!quit)
        {
            // 派发器
            Dispatcher(3000);
            PrintConnection();
        }
        quit = true;
    }

    void PrintConnection()
    {
        std::cout << "_connections fd list: " << std::endl;
        for (auto &con : _connections)
        {
            std::cout << con.second->Sockfd() << "," << std::endl;
            std::cout << "inbuffer" << con.second->Inbuffer().c_str();
        }
        std::cout << std::endl;
    }

    ~TcpServer()
    {
        listensock_ptr->Close();
    }

private:
    std::shared_ptr<Sock> listensock_ptr;
    std::shared_ptr<Epoller> Epoller_ptr;
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;
    // 为什么不能使用weak_ptr??
    // 它是弱引用，它不会增加引用计数，但无法直接解引用对象，必须的通过lock转化成shared_ptr，易错
    // 不保证对象的存活
    // std::unordered_map<int,std::weak_ptr<Connection>> _connections;

    uint16_t port_;
    struct epoll_event revs[num];
    bool quit;
    func_t OnMessage_;
};